(*  :Title:	Supporting Routines for the z-Transform  *)

(*  :Authors:	Brian Evans, James McClellan  *)

(*  :Summary:	*)

(*  :Context:	SignalProcessing`Digital`ZSupport`  *)

(*  :PackageVersion:  2.7	*)

(*
    :Copyright:	Copyright 1989-1991 by Brian L. Evans
		Georgia Tech Research Corporation

	Permission to use, copy, modify, and distribute this software
	and its documentation for any purpose and without fee is
	hereby granted, provided that the above copyright notice
	appear in all copies and that both that copyright notice and
	this permission notice appear in supporting documentation,
	and that the name of the Georgia Tech Research Corporation,
	Georgia Tech, or Georgia Institute of Technology not be used
	in advertising or publicity pertaining to distribution of the
	software without specific, written prior permission.  Georgia
	Tech makes no representations about the suitability of this
	software for any purpose.  It is provided "as is" without
	express or implied warranty.
 *)

(*  :History:	*)

(*  :Keywords:	normalized, z-transform, region of convergence	*)

(*  :Source:	*)

(*  :Warning:	*)

(*  :Mathematica Version:  1.2 or 2.0  *)

(*  :Limitation:  *)

(*
    :Functions:	  InvalidZTransformQ
		  InvalidInvZTransformQ
		  KeepNormalized
		  MakeZObject
		  ZForm
		  ZTransformQ
		  ZUpsampledQ
		  ZVariables
 *)



(*  B E G I N     P A C K A G E  *)

BeginPackage[ "SignalProcessing`Digital`ZSupport`",
	      "SignalProcessing`Support`TransSupport`",
	      "SignalProcessing`Support`ROC`",
	      "SignalProcessing`Support`SigProc`",
	      "SignalProcessing`Support`SupCode`" ]


If [ TrueQ[ $VersionNumber >= 2.0 ],
     Off[ General::spell ];
     Off[ General::spell1 ] ];


(*  U S A G E     I N F O R M A T I O N  *)

InvalidZTransformQ::usage =
	"InvalidZTransformQ[x] returns True if a call exists to \
	the function MyZTransform in expression x; that is, True \
	is returned if the result from a call to Z or ZTransform \
	was not a valid Z transform."

InvalidInvZTransformQ::usage =
	"InvalidInvZTransformQ[x] returns True if the result from a \
	call to InvZTransform was not a valid inverse z-transform. \
	This occurs when the object myinvz exists in expression x."

KeepNormalized::usage =
	"KeepNormalized[zexpr, fun, z, args] keeps the z-transform \
	expression zexpr in negative powers of z after the function \
	fun is applied to zexpr and args as fun[zexpr, args]."

MakeZObject::usage =
	"MakeZObject[l] and MakeZObject[l, zlist] converts the \
	z-transform information in list l into the standard object \
	form ZTransData[x, Rminus[rm], Rplus[rp], ZVariables[zlist]]. \
	Here, x is the z-transform, rm is the lower bound on the \
	region of convergence, rp is the upper bound on the region \
	of convergence, and zlist is the list of z variables used in \
	the transform."

ZForm::usage =
	"ZForm[x] return True if the data packet x is tagged with \
	either List or Transform and contains three elements."

ZTransformQ::usage =
	"ZTransformQ[x] returns True if the datum x is of the form \
	ZTransData[X, rm, rp, z], where X is the z-transform, rm is the \
	Rminus component of the region of convergence, rp is the \
	Rplus component of the region of convergence, and z is \
	the variable(s) in the z-transform."

ZUpsampledQ::usage =
	"ZUpsampledQ[f, n] returns True if the sequence f, as a function \
	of n, has been upsampled. \
	See UpsampleFactor."

(*  E N D     U S A G E     I N F O R M A T I O N  *)


Begin["`Private`"]


(*  E X T E N D     B U I L T - I N     R O U T I N E S  *)

(*  Denominator  *)
ZTransData/: Denominator[ZTransData[fun_, a__]] := Denominator[fun]

(*  Factor  *)
ZTransData/: Factor[ZTransData[fun_, a__]] := ZTransData[Factor[fun], a]

(*  Numerator  *)
ZTransData/: Numerator[ZTransData[fun_, a__]] := Numerator[fun]

(*  Simplify  *)
ZTransData/: Simplify[ZTransData[fun_, rm_, rp_, z_]] :=
	Block [	{replace, zvars},
		zvars = ToCollection[z];	(* strip off ZVariables head *)
		replace = zvars ~ReplaceWith~ (zvars^-1);
		ZTransData[Simplify[fun /. replace] /. replace, rm, rp, z] ]

(*  Together  *)
ZTransData/: Together[ZTransData[fun_, rm_, rp_, z_]] :=
	Block [	{replace, zvars},
		zvars = ToCollection[z];	(* strip off ZVariables head *)
		replace = zvars ~ReplaceWith~ (zvars^-1);
		ZTransData[Together[fun /. replace] /. replace, rm, rp, z] ]


(*  E X T E N D     D E F I N E D     R O U T I N E S  *)

(*  TheFunction  *)
ZTransData/: TheFunction[ZTransData[x_, rm_, rp_, z_]] := x


(*  O T H E R     S U P P O R T I N G     R O U T I N E S  *)

(*  InvalidZTransformQ, InvalidInvZTransformQ  *)
invalid[x_, h_] := If [ SameQ[Head[x], head], flag = True ];

InvalidZTransformQ[x_] :=		(* flag is exterior package data *)
	Block [	{head},
		head = SignalProcessing`Digital`ZTransform`Private`MyZTransform;
		flag = SameQ[Head[x], head];	(* exterior package data *)
		If [ ! flag, Scan[invalid[#, head]&, x, Infinity] ];
		flag ]

InvalidInvZTransformQ[x_] :=		(* flag is exterior package data *)
	Block [	{head},
		head = SignalProcessing`Digital`InvZTransform`Private`MyInvZTransform;
		flag = SameQ[Head[x], head];
		head = SignalProcessing`Digital`InvZTransform`Private`myinvz;
		If [ ! flag, flag = SameQ[Head[x], head] ];
		If [ ! flag, Scan[invalid[#, head]&, x, Infinity] ];
		flag ]

(*  KeepNormalized  *)
(*  Maintain z-transform expressions in terms of z^-1.  *)
KeepNormalized[e_, f_, z_, args___] :=
	Block [ {newexpr, zexpr},
		zexpr = e /. ReplaceWith[z, z^-1];
		newexpr =  f[zexpr, args];
		newexpr /. ReplaceWith[z, z^-1] ]

(*  MakeZObject  *)
MakeZObject[ZTransData[x_, rm_, rp_, z_]] :=
	ZTransData[x, rm, Rplus[ GetRPlus[rp] ], z]
MakeZObject[x_List] :=
	ZTransData[ x[[1]], Rminus[ x[[2]] ], Rplus[ InfCheck[x[[3]]] ] ]
MakeZObject[x_, z_] :=
	ZTransData[ x[[1]], Rminus[ x[[2]] ],
		    Rplus[ InfCheck[x[[3]]] ], ZVariables[ z ] ] /;
	ZForm[x]

Format[ MakeZObject[a__] ] := "-Incomplete z-Transform-"

(*  ZForm  *)
ZForm[Transform[x_, rm_, rp_]] := True
ZForm[List[x_, rm_, rp_]] := True

(*  ZTransformQ  *)
ZTransformQ[x_] := SameQ[Head[x], ZTransData]

(*  ZUpsampledQ  *)
ZUpsampledQ[f_, n_] :=
	Block [	{upindex},
		upindex = UpsampleFactor[f, n];	  (* returns pos & neg nums *)
		Implies[ NumberQ[N[upindex]], N[Abs[upindex] > 1]] ]


(*  E N D     P A C K A G E  *)

End[]
EndPackage[]

If [ TrueQ[ $VersionNumber >= 2.0 ],
     On[ General::spell ];
     On[ General::spell1 ] ];


(*  H E L P     I N F O R M A T I O N  *)

Block [	{newfuns},
	newfuns =
	  { InvalidZTransformQ,	InvalidInvZTransformQ,	KeepNormalized,
	    MakeZObject,	ZUpsampledQ,		ZTransformQ,
	    ZVariables };
	Combine[ SPfunctions, newfuns ];
	Apply[ Protect, newfuns ] ]


(*  E N D I N G     M E S S A G E  *)

Print["Supporting routines for the z-transform rule bases are loaded."]
Null
